package com.emergency.embackend.service.impl;

import com.emergency.embackend.common.PageParams;
import com.emergency.embackend.entity.Article;
import com.emergency.embackend.entity.Video;
import com.emergency.embackend.mapper.OperateMapper;
import com.emergency.embackend.param.ArticleDataParam;
import com.emergency.embackend.param.VideoDataParam;
import com.emergency.embackend.exception.EmException;
import com.emergency.embackend.mapper.WikiVideoMapper;
import com.emergency.embackend.param.VideoParam;
import com.emergency.embackend.service.DataViewService;
import com.emergency.embackend.service.OperateService;
import com.emergency.embackend.service.WikiVideoService;
import com.emergency.embackend.utils.RecommendUtils;
import com.emergency.embackend.utils.RedisConstants;
import com.emergency.embackend.utils.UserHolder;
import com.emergency.embackend.vo.ArticleVO;
import com.emergency.embackend.vo.VideoVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @author chddd
 * @description
 * @create 2024/2/25 21:30:24
 */
@Service
public class WikiVideoServiceImpl implements WikiVideoService {

    @Autowired
    private WikiVideoMapper wikiVideoMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private OperateService operateService;

    @Autowired
    private DataViewService dataViewService;
    @Autowired
    private OperateMapper operateMapper;

    @Override
    public PageInfo getVideoData(VideoDataParam videoDataParam) {
        PageHelper.startPage(videoDataParam.getPageNum(), videoDataParam.getPageSize());
        List<Video> resList = wikiVideoMapper.getVideoData(videoDataParam);
        resList.forEach(e->{
            e.setViewCount(dataViewService.getViewCount(RedisConstants.VIEW_VIDEO_COUNT_KEY+e.getId())+e.getViewCount());
            e.setLikeCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_LIKE_COUNT+e.getId()));
            e.setCollectCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_COLLECT_COUNT+e.getId()));
        });
        PageInfo pageInfo = new PageInfo(resList);
        return pageInfo;
    }



    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long videoId) {
        wikiVideoMapper.delete(videoId);
        stringRedisTemplate.delete(RedisConstants.VIDEO_COLLECT_COUNT+videoId);
        stringRedisTemplate.delete(RedisConstants.VIDEO_LIKE_COUNT+videoId);
        stringRedisTemplate.delete(RedisConstants.VIEW_VIDEO_COUNT_KEY+videoId);
        stringRedisTemplate.delete(RedisConstants.VIEW_VIDEO_REPEAT_KEY+videoId);
    }

    @Override
    public void deleteByTypeId(Long typeId) {
        wikiVideoMapper.deleteByTypeId(typeId);
    }

    @Override
    public void update(VideoParam videoParam) {
        videoParam.setUpdateTime(new Date());
        wikiVideoMapper.update(videoParam);
    }

    @Override
    public void add(VideoParam videoParam) {
        Date date = new Date();
        videoParam.setCreateTime(date);
        videoParam.setUpdateTime(date);
        wikiVideoMapper.add(videoParam);
    }

    @Override
    public VideoVO getOne(Long videoId) {
        VideoVO videoVo = wikiVideoMapper.getOne(videoId);
        if (videoVo == null) {
            throw new EmException("500", "查询结果为空");
        }
        if (UserHolder.getUser() == null) {
            operateService.addViews(videoId, null,'0');
        } else {
            Long userId = UserHolder.getUser().getId();
            operateService.addViews(videoId, userId,'0');
            videoVo.setIsLike(isLike(videoId, userId));
            videoVo.setIsCollect(isCollect(videoId, userId));
        }
        videoVo.setViewCount(dataViewService.getViewCount(RedisConstants.VIEW_VIDEO_COUNT_KEY + videoId) +videoVo.getViewCount());
        videoVo.setLikeCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_LIKE_COUNT+videoId));
        videoVo.setCollectCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_COLLECT_COUNT+videoId));
        return videoVo;
    }
    @Override
    public PageInfo getVideosByCreateTimeDesc(PageParams pageParams) {
        PageHelper.startPage(pageParams.getPageNum(), pageParams.getPageSize());
        List<Video> res = wikiVideoMapper.selectVideosByCreateTimeDesc();
        res.forEach(e->{
            e.setViewCount(dataViewService.getViewCount(RedisConstants.VIEW_VIDEO_COUNT_KEY+e.getId())+e.getViewCount());
            e.setLikeCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_LIKE_COUNT+e.getId()));
            e.setCollectCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_COLLECT_COUNT+e.getId()));
        });
        PageInfo pageInfo = new PageInfo(res);
        return pageInfo;
    }

    @Override
    public List<Video> getHotVideo() {
        List<Video> hotVideo = wikiVideoMapper.getHotVideo();
        if(hotVideo == null ){
            throw new EmException("500","未获取到最热数据..");
        }
        hotVideo.forEach(e->{
            e.setViewCount(dataViewService.getViewCount(RedisConstants.VIEW_VIDEO_COUNT_KEY+e.getId())+e.getViewCount());
            e.setLikeCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_LIKE_COUNT+e.getId()));
            e.setCollectCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_COLLECT_COUNT+e.getId()));
        });
        return hotVideo;
    }

    @Override
    public List<Video> getRecommendVideo(VideoDataParam videoDataParam) {
        List<Video> videoData = wikiVideoMapper.getVideoData(videoDataParam);
        Random random = new Random();
        //从redis中获取对应的点赞数和收藏数
        videoData.forEach(e->{
            e.setViewCount(dataViewService.getViewCount(RedisConstants.VIEW_VIDEO_COUNT_KEY+e.getId())+e.getViewCount());
            e.setLikeCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_LIKE_COUNT+e.getId()));
            e.setCollectCount(operateService.getLikeOrCollectCount(RedisConstants.VIDEO_COLLECT_COUNT+e.getId()));
        });
        List<Video> resList = new ArrayList<>();
        Long userId = videoDataParam.getUserId();
        Collections.shuffle(videoData,random);
        if(userId==null){
            if(videoDataParam.getLimitNum()!=null){
                return videoData.subList(0,videoDataParam.getLimitNum().intValue());
            }
            return videoData;
        }
        String key = RedisConstants.VIEW_ARTICLE_HISTORY_KEY+userId;
        //从redis获取用户浏览过的视频的历史
        Set<String> history = stringRedisTemplate.opsForZSet().range(key, 0, -1);
        //以视频类型id 为key,该类型对应的 值次数为value
        Map<Long, Integer> map = new HashMap<>();
        if(history!=null && history.size()!=0) {
            List<Long> videoIds = history.stream().map(e -> Long.parseLong(e)).collect(Collectors.toList());
            buildDataType(videoIds,map);
        }
        //在从数据库获取用户点赞和收藏的对应的视频数据
        List<Long> likeIds =  operateMapper.getLikeData("0",userId);
        if(likeIds!=null && likeIds.size()!=0){
            buildDataType(likeIds,map);
        }
        List<Long> collectIds =operateMapper.getCollectData("0",userId);
        if(collectIds!=null && collectIds.size()!=0){
            buildDataType(collectIds,map);
        }
        //通过map集合存储每种类型 该用户浏览的类型比例
        if(map.isEmpty()){
            if(videoDataParam.getLimitNum()!=null){
                return videoData.subList(0,videoDataParam.getLimitNum().intValue());
            }
            return videoData;
        }
        //根据 类型的value值进行排序
        List<Long> typeIds = map.entrySet().stream().sorted(Collections
                        .reverseOrder(Map.Entry.comparingByValue()))
                .map(Map.Entry::getKey).collect(Collectors.toList());
        //根据该类型比例去获取对应的文章数据
        int limitNum = -1 ;
        if(videoDataParam.getLimitNum()!=null){
            limitNum = videoDataParam.getLimitNum().intValue();
        }
        for (Long typeId : typeIds) {
            VideoDataParam  param = new VideoDataParam();
            param.setTypeId(typeId);
            List<Video> recommendData = wikiVideoMapper.getVideoData(param);
            Collections.shuffle(recommendData);
            if(limitNum>0){
                if(recommendData.size()>=limitNum){
                    resList.addAll(recommendData.subList(0,limitNum));
                    break;
                }else{
                    limitNum -=recommendData.size();
                    resList.addAll(recommendData);
                }
            }else {
                resList.addAll(recommendData);
            }
        }
        return resList;
    }

    @Override
    public List<Video> getHistory(Long userId) {
        //获取对应的文章id值
        List<Video> resList = null;
        String key = RedisConstants.VIEW_VIDEO_HISTORY_KEY+userId;
        if(Boolean.TRUE.equals(stringRedisTemplate.hasKey(key))) {
            List<Long> videoIds = new ArrayList<>();
            Set<String> set = stringRedisTemplate.opsForZSet().range(key, 0, -1);
            if(set!=null && set.size()!=0){
                videoIds = set.stream().map(Long::parseLong).collect(Collectors.toList());
                resList = wikiVideoMapper.getHistoryArticle(videoIds);
            }

        }
        return resList;
    }

    /**
     * 用于构建对应的视频类型的次数
     * @param videoIds
     * @param map
     */
    private void buildDataType(List<Long> videoIds, Map<Long, Integer> map) {
        List<Long> typeIds = wikiVideoMapper.getTypeIds(videoIds);
        typeIds.forEach(e->{
            map.put(e,map.getOrDefault(e,0)+1);
        });
    }

    private Boolean isLike(Long videoId,Long userId){
        String key = RedisConstants.VIDEO_LIKE_USER + videoId;
        Boolean flag = false;
        if(Boolean.TRUE.equals(stringRedisTemplate.hasKey(key))){
            flag = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        }
        return flag;
    }
    private Boolean isCollect(Long videoId,Long userId){
        String key = RedisConstants.VIDEO_COLLECT_USER + videoId;
        Boolean flag = false;
        if(Boolean.TRUE.equals(stringRedisTemplate.hasKey(key))){
            flag = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        }
        return flag;
    }
}
